//
// Created by Administrator on 2016/11/29.
//

#include "Light.h"
#include "Material.h"

using namespace ZainGL;
using namespace glm;

GLuint Light::ShadowFBO=0;
GLuint Light::ShadowMapTextureLoc=0;

void Light::beginRenderToShadowMap(int32_t width, int32_t height, GLuint shaderLoc) {
    glBindFramebuffer(GL_FRAMEBUFFER, ShadowFBO);
    glViewport(0, 0, width, height);
    glClear(GL_DEPTH_BUFFER_BIT);
    glCullFace(GL_FRONT);// Culling switching, rendering only backface, this is done to avoid self-shadowing
    glUseProgram(shaderLoc);
}

void Light::endRenderToShadowMap() {
    glCullFace(GL_BACK); // don't forget to reset original culling face
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Light::recreateShadowMap(GLuint width, GLuint height) {
    if (ShadowMapTextureLoc){
        glDeleteTextures(1,&ShadowMapTextureLoc);
    }
    //create a 2D texture that we'll use as the framebuffer's depth buffer
    glGenTextures(1, &ShadowMapTextureLoc);
    glActiveTexture(GL_TEXTURE0);//我默认让ShadowMap绑定在GL_TEXTURE0上
    glBindTexture(GL_TEXTURE_2D, ShadowMapTextureLoc);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    /*
     * https://www.opengl.org/discussion_boards/showthread.php/169597-GLSL-ShadowMap
     * If you "do" want hardware depth comparisons, use a *Shadow sampler (e.g. sampler2DShadow), enable depth comparisons on the texture, and use a shadow* texture sampling function in your shader (if using GLSL 1.2 or earlier, else just use texture*).
     * If you "do not" want hardware depth comparisons, use a non-*Shadow sampler (e.g. sampler2D), disable hardware depth comparisons, and use a non-shadow* texture sampling function (again if GLSL 1.2 or earlier; otherwise just use texture*). If you "do" want hardware depth comparisons, use a *Shadow sampler (e.g. sampler2DShadow), enable depth comparisons on the texture, and use a shadow* texture sampling function in your shader (if using GLSL 1.2 or earlier, else just use texture*).
     * If you "do not" want hardware depth comparisons, use a non-*Shadow sampler (e.g. sampler2D), disable hardware depth comparisons, and use a non-shadow* texture sampling function (again if GLSL 1.2 or earlier; otherwise just use texture*). */
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    /*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);*/
    /*使用以下方法可以让ShadowMap之外的深度值为最深，防止因shadowmap分辨率太小导致外部场景陷入阴影*/
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    GLfloat borderColor[] = { 1.0, 1.0, 1.0, 1.0 };
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

    if (ShadowFBO){
        glDeleteFramebuffers(1,&ShadowFBO);
    }
    glGenFramebuffers(1, &ShadowFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, ShadowFBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, ShadowMapTextureLoc, 0);
    glDrawBuffer(GL_NONE);//explicitly tell OpenGL we're not going to render any color data
    glReadBuffer(GL_NONE);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        printf("FBO error, status: 0x%x\n", status);
    }
}
